﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Jerry.DroidBuilder.Common;
using Jerry.DroidBuilder.Properties;

namespace Jerry.DroidBuilder.Helpers
{
    public static class DeodexHelper
    {
        public static void DoDeodex(string currentDirectory)
        {
            var odexs = new List<string>(Directory.GetFiles(currentDirectory, "*.odex", SearchOption.AllDirectories));
            var frameworkPath = Directory.GetFiles(currentDirectory, "framework.jar", SearchOption.AllDirectories);
            var frameworkDirectory = string.Empty;
            //var honeycombFramework = string.Empty;

            if (frameworkPath.Length > 0)
            {
                frameworkDirectory = Path.GetDirectoryName(frameworkPath[0]);
            }

            //if (string.IsNullOrEmpty(frameworkDirectory))
            //{
            //    // TODO:
            //}
            //else
            //{
            //    honeycombFramework = Path.Combine(frameworkDirectory, "framework.honeycomb.jar");
            //    File.Copy(Path.Combine(Util.ToolsDirectory, "framework.honeycomb.jar"), honeycombFramework);
            //}

            odexs.Sort();

            foreach (var item in odexs)
            {
                StatusReport.Update(string.Format(Lang.Deodex_Processing, item.Replace(currentDirectory, string.Empty)));

                if (Directory.Exists(".\\out"))
                {
                    Directory.Delete(".\\out", true);
                }

                #region Using baksmali to expand odex file

                try
                {
                    Connector.Baksmali(frameworkDirectory, item);
                }
                catch (Exception ex)
                {
                    ExceptionLogger.Log(ex);
                    Util.ShowMessage(string.Format(Lang.Deodex_Error, Path.GetFileName(item), ex.Message));
                    continue;
                }

                #endregion

                #region Using smali to compile out folder

                var target = item.Replace(".odex", ".apk");
                var classesDex = Path.Combine(Util.ApplicationDirectory, "classes.dex");

                if (target.StartsWith(frameworkDirectory))
                {
                    target = target.Replace(".apk", ".jar");
                }

                try
                {
                    Connector.Smali();
                }
                catch (Exception ex)
                {
                    Util.ShowMessage(string.Format(Lang.Deodex_Error, Path.GetFileName(item), ex.Message));
                    continue;
                }

                if (File.Exists(target) && File.Exists(classesDex))
                {
                    PackageHelper.UpdateFile(target, classesDex);
                    File.Delete(item);
                }

                #endregion
            }

            //if (!string.IsNullOrEmpty(honeycombFramework) && File.Exists(honeycombFramework))
            //{
            //    File.Delete(honeycombFramework);
            //}

            StatusReport.Update(Lang.Deodex_Done);
        }

        //private static RomItem FindItem(ObservableCollection<RomItem> items, string name)
        //{
        //    RomItem result = null;

        //    foreach (var item in items)
        //    {
        //        if (item.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
        //        {
        //            result = item;
        //            break;
        //        }
        //    }

        //    return result;
        //}

        public static void DoDexopt(string currentDirectory, string remoteTemp, bool useEmu)
        {
            Process emulator = null;

            var result = AdbCommand("remount", useEmu);

            if (string.Empty != result && useEmu)
            {
                StatusReport.Update(Lang.Dexopt_StartEmulator);
                Connector.ExecuteCommand("emulator", string.Format(" -data \"{0}\\dexopt.img\" -noaudio -no-boot-anim -noskin -no-window", Util.ToolsDirectory), true, out emulator);
            }

            while (string.Empty != result)
            {
                result = AdbCommand("remount", useEmu);
                Thread.Sleep(500);
            }

            StatusReport.Update(Lang.Dexopt_EmulatorConnected);

            const string DEXOPT_WRAPPER = "dexopt-wrapper";
            const string CLASSES_DEX = "classes.dex";

            var local = Path.Combine(Util.ToolsDirectory, DEXOPT_WRAPPER);
            var remote = Path.Combine(remoteTemp, DEXOPT_WRAPPER);

            AdbCommand(string.Format("push \"{0}\" \"{1}\"", local, remote), useEmu);
            AdbCommand(string.Format("shell chmod 755 \"{0}\"", remote), useEmu);

            var packages = new List<string>();

            packages.AddRange(Directory.GetFiles(currentDirectory, "*.jar", SearchOption.AllDirectories));
            packages.AddRange(Directory.GetFiles(currentDirectory, "*.apk", SearchOption.AllDirectories));

            foreach (var file in packages)
            {
                if (!PackageHelper.Contains(file, CLASSES_DEX))
                {
                    continue;
                }

                var localOdex = file.Replace(".jar", ".odex").Replace(".apk", ".odex");

                var name = Path.GetFileName(file);
                var odexName = Path.GetFileName(localOdex);

                StatusReport.Update(Lang.Dexopt_ProcessItem, name);

                AdbCommand(string.Format("push \"{0}\" \"{1}\"", file, remoteTemp), useEmu);
                AdbCommand(string.Format("shell \"{0}\" \"{1}/{2}\" \"{1}/{3}\"", remote, remoteTemp, name, odexName), useEmu);
                AdbCommand(string.Format("pull \"{0}/{1}\" \"{2}\"", remoteTemp, odexName, localOdex), useEmu);
                AdbCommand(string.Format("shell rm \"{0}/{1}\"", remoteTemp, name), useEmu);
                AdbCommand(string.Format("shell rm \"{0}/{1}\"", remoteTemp, odexName), useEmu);

                PackageHelper.Delete(file, CLASSES_DEX);
            }

            if (null != emulator)
            {
                StatusReport.Update(Lang.Dexopt_CloseEmulator);
                emulator.Kill();
                StatusReport.Update(Lang.Dexopt_CloseEmulatorCompleted);
            }

            StatusReport.Update(Lang.Dexopt_Completed);
        }

        private static string AdbCommand(string arguments, bool useEmulator)
        {
            if (!arguments.StartsWith(" "))
            {
                arguments = " " + arguments;
            }

            if (useEmulator)
            {
                arguments = " -e" + arguments;
            }

            return Connector.ExecuteCommand("adb", arguments);
        }
    }
}
